package com.pc_project.service.impl;

import com.pc_project.domain.Roles;
import com.pc_project.domain.User;
import com.pc_project.domain.VO.JsonVO;
import com.pc_project.domain.VO.UserLogin;
import com.pc_project.domain.authenticate.AuditAuthenticator;
import com.pc_project.domain.authenticate.UserAuthenticator;
import com.pc_project.mapper.UserDao;
import com.pc_project.service.UserService;
import com.pc_project.utils.RedisCache;
import com.pc_project.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private RedisCache redisCache;
    //    利用注入到容器的AuthenticationManager来进行authenticate方法认证
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserLogin userLogin;

    @Autowired
    private UserDao userDao;

    //   生成加密的密码加密器
    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    public JsonVO login(String username, String password) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//        如果认证不成功那么对象就会为空。
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("用户名或密码错误");
        }
//        认证成功我们就生成token
        UserAuthenticator userAuthenticator = (UserAuthenticator) authenticate.getPrincipal();
        User user = userAuthenticator.getUser();
        String uid = user.getUid().toString();
        String jwt = TokenUtils.createToken(uid);
//        将完整信息存入redis
        redisCache.setCacheObject("login:" + uid, userAuthenticator);
//        存入redis后将信息返回给前端
        HashMap<String, Object> map = new HashMap<>();
        userLogin.setMail(user.getMail());
        userLogin.setUsername(user.getUsername());
        userLogin.setNickname(user.getNickname());
        userLogin.setRole(user.getRole());
        userLogin.setToken(jwt);
        userLogin.setUid(user.getUid());
        map.put("user", userLogin);
//        更新用户登录时间数据
        userDao.updateByPrimaryKey(user);
        return JsonVO.success(map);
    }

    @Override
    public JsonVO logout() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserAuthenticator userAuthenticator = (UserAuthenticator) authentication.getPrincipal();
        Integer userid = userAuthenticator.getUser().getUid();
        redisCache.deleteObject("login:" + userid);
        return JsonVO.success("注销成功");
    }

    @Override
    public JsonVO reg(User userRequest) {
        User user = new User();
        if (Integer.parseInt(userRequest.getRole()) == 0) {
            user.setRole(Roles.USER.getName());
        } else if (Integer.parseInt(userRequest.getRole()) == 1) {
            user.setRole(Roles.REPLYUSER.getName());
        } else {
            return JsonVO.fail("角色输入不规范");
        }
//        密码要进行加密
        String password = passwordEncoder.encode(userRequest.getPassword());
        user.setPassword(password);
//        用户id最好用雪花算法之类的，不过现在从简也可以用数据库自带的自动递增
        user.setUsername(userRequest.getUsername());
        user.setMail(userRequest.getMail());
        user.setNickname(userRequest.getNickname());
        user.setLastUpdate(new Date());
        try {
            userDao.insert(user);
        } catch (Exception e) {
            e.printStackTrace();
            return JsonVO.fail(null);
        }
        return JsonVO.success(null);
    }

    @Override
    public JsonVO<String> updatePwd(String oldPwd, String newPwd) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserAuthenticator userAuthenticator = (UserAuthenticator) authentication.getPrincipal();
        User curUser = userAuthenticator.getUser();
        String userName = curUser.getUsername();

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, oldPwd);
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//        如果认证不成功那么对象就会为空。
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("出现错误");
        }
        //认证成功修改密码
        String password = passwordEncoder.encode(newPwd);
        curUser.setPassword(password);
        userDao.updateByPrimaryKey(curUser);
        //退出登陆
        redisCache.deleteObject("login:" + curUser.getUid());

        return JsonVO.success("修改成功，请重新登陆");
    }
}
